﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using System.Web.SessionState;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Jim.Obsidian.Utilities;
using Jim.Obsidian.Edm;

namespace Jim.Obsidian.Web.Api
{
    public class ApiHandler : IHttpHandler, IRequiresSessionState
    {

        private string PN_NAME = "name";
        private string PN_APP_KEY = "appkey";
        private string _status = "#OK#";
        private string _msg = "";

        public void ProcessRequest(HttpContext context)
        {
            string jsonText = ParamsReceiver.GetRequestInputStreamString();
            if (!String.IsNullOrEmpty(jsonText))
            {
                JObject jo = (JObject)JsonConvert.DeserializeObject(jsonText);
                if (VerifyParameters(jo))
                {
                    JArray jarr = (JArray)jo["reqs"];
                    ApiRequest[] apiRequests = this.JArrayToApiRequests(jarr);
                    this.ExecuteRequests(apiRequests);
                }
                else
                {
                    context.Response.Write("传入参数错误!");
                }
            }
            else
            {
                context.Response.Write("hello world!");
            }
        }

        public string Status
        {
            get { return this._status; }
            set { this._status = value; }
        }

        private bool VerifyParameters(JObject jo)
        {
            string name = Convert.ToString(((JValue)jo["appName"]).Value);
            string appkey = Convert.ToString(((JValue)jo["appKey"]).Value);
            string sign = Convert.ToString(((JValue)jo["sign"]).Value);
            string timestamp = Convert.ToString(((JValue)jo["timestamp"]).Value);
            List<string> paramsList = new List<string>();
            paramsList.Add("appName=" + name);
            paramsList.Add("appKey=" + appkey);
            paramsList.Add("timestamp=" + timestamp);
            JArray jarr = (JArray)jo["reqs"];
            foreach (JToken jt in jarr)
            {
                JObject o = (JObject)jt;
                paramsList.Add(this.RequestParamsSortByString(o));
            }
            paramsList.Sort();
            string strParams = ArrayUtility.Join(paramsList, "&");
            return StringUtility.AspMD5(strParams).Equals(sign);
        }

        private string RequestParamsSortByString(JObject jo)
        {
            JValue jv = (JValue)jo["act"];
            string act = Convert.ToString(jv.Value);
            List<string> paramsList = new List<string>();
            paramsList.Add("act=" + act);
            JObject jd = (JObject)jo["data"];
            if (jd != null)
            {
                IEnumerable<JProperty> jprops = jd.Properties();
                foreach (JProperty jp in jprops)
                    paramsList.Add(jp.Name + "=" + Convert.ToString(((JValue)jp.Value).Value));
            }
            paramsList.Sort();
            return ArrayUtility.Join(paramsList, "&");
        }

        public ApiRequest[] JArrayToApiRequests(JArray jarr)
        {
            ApiRequest[] reqs = new ApiRequest[jarr.Count];
            for (int i = 0; i < jarr.Count; i++)
                reqs[i] = new ApiRequest((JObject)jarr[i]);
            return reqs;
        }

        public void ExecuteRequests(ApiRequest[] apiRequests)
        {
            foreach (ApiRequest req in apiRequests)
                this.ExecuteRequest(req);
            this.OutputResultSet(apiRequests);
        }

        private void OutputResultSet(ApiRequest[] apiRequests)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("{\"st\":\"" + this._status + "\",");
            sb.Append("\"sdt\":\"" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") + "\",");
            sb.Append("\"rsus\":[");
            foreach (ApiRequest req in apiRequests)
            {
                sb.Append(req.GetResultsJsonString());
                sb.Append(",");
            }
            sb.Remove(sb.Length - 1, 1);
            sb.Append("]}");
            HttpResponse response = HttpContext.Current.Response;
            response.Write(sb.ToString());
            response.End();
        }

        protected virtual void ExecuteRequest(ApiRequest req)
        {
            string typeName = req.TypeName;
            string methodName = req.MethodName;
            Type t = Type.GetType(typeName);
            if (t == null)
            {
                req.Message = "找不到该名称接口";
                return;
            }
            object obj = Activator.CreateInstance(t);
            obj.GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, new Object[] { this });
        }

        public virtual void OnRequest(HttpContext context) { }

        public virtual void OnError(HttpContext context, Exception e) { }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

    }
}
